using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Reflection.Emit;
using NBear.Common;

namespace NBear.Tools.EntityImpl
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                txtFileName.Text = openFileDialog1.FileName;
                btnGen.Enabled = true;
            }
        }

        private void btnGen_Click(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            Assembly ass = Assembly.LoadFrom(txtFileName.Text);

            if (outputLanguage.SelectedIndex == 0)
            {
                sb.Append("namespace EntityImpl\r\n{\r\n");

                foreach (Type type in ass.GetTypes())
                {
                    if (type.IsInterface && typeof(IEntity).IsAssignableFrom(type))
                    {
                        GenEntity(sb, type);
                    }
                }

                sb.Append("}\r\n");
            }
            else if (outputLanguage.SelectedIndex == 1)
            {
                sb.Append("Namespace EntityImpl\r\n");

                foreach (Type type in ass.GetTypes())
                {
                    if (type.IsInterface && typeof(IEntity).IsAssignableFrom(type))
                    {
                        GenEntityVB(sb, type);
                    }
                }

                sb.Append("End Namespace\r\n");
            }

            output.Text = sb.ToString();
        }

        private void GenEntity(StringBuilder sb, Type type)
        {
            sb.Append(string.Format("\tpublic class {0} : Entity<{1}>, {1}\r\n", type.Name, type.FullName));
            sb.Append("\t{\r\n");

            sb.Append(string.Format("\t\tpublic {0}() : base()", type.Name));
            sb.Append(" { }\r\n\r\n");

            int i = 0;
            foreach (PropertyInfo pi in Util.DeepGetProperties(type))
            {
                object[] attrs = pi.GetCustomAttributes(typeof(CustomPropertyAttribute), false);

                sb.Append(string.Format("\t\tpublic {1} {0}\r\n", pi.Name, GenType(pi.PropertyType.ToString())));
                sb.Append("\t\t{\r\n");
                sb.Append("\t\t\tget { ");
                if (attrs != null && attrs.Length > 0)
                {
                    CustomPropertyAttribute cpa = (CustomPropertyAttribute)attrs[0];

                    sb.Append(string.Format("return new {0}(keyValues", pi.PropertyType.ToString()));
                    if (cpa.Parameters != null && cpa.Parameters.Length > 0)
                    {
                        int k = 0;
                        foreach (string val in cpa.Parameters)
                        {
                            if (k == 0)
                            {
                                sb.Append(", new String[] { ");
                                sb.Append(string.Format("\"{0}\"", val.Replace("\"", "\\\"")));
                            }
                            else
                            {
                                sb.Append(string.Format(", \"{0}\"", val.Replace("\"", "\\\"")));
                            }

                            if (k == cpa.Parameters.Length - 1)
                            {
                                sb.Append(" }");
                            }

                            k++;
                        }
                    }
                    sb.Append("); ");
                }
                else
                {
                    sb.Append(string.Format("return ({1})keyValues[{0}]; ", i, GenType(pi.PropertyType.ToString())));
                }
                sb.Append("}\r\n");

                if (pi.CanWrite || checkIsGenSetMethodAllTheTime.Checked)
                {
                    sb.Append("\t\t\tset \r\n\t\t\t{ \r\n");
                    sb.Append("\t\t\t\tbase.CheckOriginalKeyValues();\r\n");
                    sb.Append(string.Format("\t\t\t\tkeyValues[{0}] = value;\r\n", i));
                    sb.Append("\t\t\t}\r\n");
                }
                sb.Append("\t\t}\r\n\r\n");

                i++;
            }

            sb.Append("\t\tpublic KeyValueCollection GetKeyValues() { return keyValues; }\r\n\r\n");
            sb.Append("\t\tpublic new KeyValueCollection GetOriginalKeyValues() { return base.GetOriginalKeyValues(); }\r\n\r\n");
            sb.Append("\t\tpublic new void UpdateOriginalKeyValues() { base.UpdateOriginalKeyValues(); }\r\n\r\n");

            sb.Append("\t}\r\n\r\n");
        }

        private void GenEntityVB(StringBuilder sb, Type type)
        {
            sb.Append(string.Format("\tPublic Class {0}\r\n\tInherits Entity(Of {1})\r\n \tImplements {1}\r\n", type.Name, type.FullName));

            sb.Append("\t\tPublic Sub New()\r\n\t\t\tMyBase.New\r\n");
            sb.Append("\t\tEnd Sub\r\n\r\n");

            int i = 0;
            foreach (PropertyInfo pi in Util.DeepGetProperties(type))
            {
                object[] attrs = pi.GetCustomAttributes(typeof(CustomPropertyAttribute), false);

                if (pi.CanWrite || checkIsGenSetMethodAllTheTime.Checked)
                {
                    sb.Append("\t\tPublic ");
                }
                else
                {
                    sb.Append("\t\tPublic ReadOnly ");
                }

                sb.Append(string.Format("Property {0} As {1} Implements {2}.{0}\r\n", pi.Name, GenTypeVB(pi.PropertyType.ToString()), type.FullName));
                sb.Append("\t\t\tGet\r\n");
                if (attrs != null && attrs.Length > 0)
                {
                    CustomPropertyAttribute cpa = (CustomPropertyAttribute)attrs[0];

                    sb.Append(string.Format("\t\t\t\tReturn new {0}(keyValues", pi.PropertyType.ToString()));
                    if (cpa.Parameters != null && cpa.Parameters.Length > 0)
                    {
                        int k = 0;
                        foreach (string val in cpa.Parameters)
                        {
                            if (k == 0)
                            {
                                sb.Append(", New String() { ");
                                sb.Append(string.Format("\"{0}\"", val.Replace("\"", "\\\"")));
                            }
                            else
                            {
                                sb.Append(string.Format(", \"{0}\"", val.Replace("\"", "\\\"")));
                            }

                            if (k == cpa.Parameters.Length - 1)
                            {
                                sb.Append(" }");
                            }

                            k++;
                        }
                    }
                    sb.Append(")\r\n");
                }
                else
                {
                    sb.Append(string.Format("\t\t\t\tReturn CType(keyValues({0}), {1})\r\n", i, GenTypeVB(pi.PropertyType.ToString())));
                }
                sb.Append("\t\t\tEnd Get\r\n");

                if (pi.CanWrite || checkIsGenSetMethodAllTheTime.Checked)
                {
                    sb.Append("\t\t\tSet \r\n");
                    sb.Append("\t\t\t\tMyBase.CheckOriginalKeyValues\r\n");
                    sb.Append(string.Format("\t\t\t\tkeyValues({0}) = value\r\n", i));
                    sb.Append("\t\t\tEnd Set\r\n");
                }
                sb.Append("\t\tEnd Property\r\n\r\n");

                i++;
            }

            sb.Append(string.Format("\t\tPublic Function GetKeyValues() As KeyValueCollection Implements {0}.GetKeyValues\r\n\t\t\tReturn keyValues\r\n\t\tEnd Function\r\n\r\n", type.FullName));
            sb.Append(string.Format("\t\tPublic Shadows Function GetOriginalKeyValues() As KeyValueCollection Implements {0}.GetOriginalKeyValues\r\n\t\t\tReturn MyBase.GetOriginalKeyValues()\r\n\t\tEnd Function\r\n\r\n", type.FullName));
            sb.Append(string.Format("\t\tPublic Shadows Sub UpdateOriginalKeyValues() Implements {0}.UpdateOriginalKeyValues\r\n\t\t\tMyBase.UpdateOriginalKeyValues()\r\n\t\tEnd Sub\r\n\r\n", type.FullName));

            sb.Append("\tEnd Class\r\n\r\n");
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            outputLanguage.SelectedIndex = 0;
        }

        private void copyAllToClipboardToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Clipboard.SetText(output.Text);
        }

        private string GenType(string typeStr)
        {
            if (typeStr == typeof(string).ToString())
            {
                return "string";
            }
            else if (typeStr == typeof(int).ToString())
            {
                return "int";
            }
            else if (typeStr == typeof(long).ToString())
            {
                return "long";
            }
            else if (typeStr == typeof(short).ToString())
            {
                return "short";
            }
            else if (typeStr == typeof(byte).ToString())
            {
                return "byte";
            }
            else if (typeStr == typeof(byte[]).ToString())
            {
                return "byte[]";
            }
            else if (typeStr == typeof(bool).ToString())
            {
                return "bool";
            }
            else if (typeStr == typeof(decimal).ToString())
            {
                return "decimal";
            }
            else if (typeStr == typeof(char).ToString())
            {
                return "char";
            }
            else if (typeStr == typeof(sbyte).ToString())
            {
                return "sbyte";
            }
            else if (typeStr == typeof(float).ToString())
            {
                return "float";
            }
            else if (typeStr == typeof(double).ToString())
            {
                return "double";
            }
            else if (typeStr == typeof(object).ToString())
            {
                return "object";
            }
            else if (typeStr == typeof(Guid).ToString())
            {
                return "Guid";
            }
            else if (typeStr == typeof(DateTime).ToString())
            {
                return "DateTime";
            }
            else
            {
                return typeStr;
            }
        }

        private string GenTypeVB(string typeStr)
        {
            if (typeStr == typeof(string).ToString())
            {
                return "String";
            }
            else if (typeStr == typeof(int).ToString())
            {
                return "Integer";
            }
            else if (typeStr == typeof(uint).ToString())
            {
                return "UInteger";
            }
            else if (typeStr == typeof(long).ToString())
            {
                return "Long";
            }
            else if (typeStr == typeof(ulong).ToString())
            {
                return "ULong";
            }
            else if (typeStr == typeof(short).ToString())
            {
                return "Short";
            }
            else if (typeStr == typeof(ushort).ToString())
            {
                return "UShort";
            }
            else if (typeStr == typeof(byte).ToString())
            {
                return "Byte";
            }
            else if (typeStr == typeof(byte[]).ToString())
            {
                return "Byte()";
            }
            else if (typeStr == typeof(bool).ToString())
            {
                return "Boolean";
            }
            else if (typeStr == typeof(decimal).ToString())
            {
                return "Decimal";
            }
            else if (typeStr == typeof(char).ToString())
            {
                return "Char";
            }
            else if (typeStr == typeof(sbyte).ToString())
            {
                return "SByte";
            }
            else if (typeStr == typeof(Single).ToString())
            {
                return "Single";
            }
            else if (typeStr == typeof(double).ToString())
            {
                return "Double";
            }
            else if (typeStr == typeof(object).ToString())
            {
                return "Object";
            }
            else if (typeStr == typeof(Guid).ToString())
            {
                return "Guid";
            }
            else if (typeStr == typeof(DateTime).ToString())
            {
                return "Date";
            }
            else
            {
                return typeStr.Replace("[", "(").Replace("]", ")");
            }
        }

    }
}